package com.kandinfo.base.security.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.kandinfo.base.admin.constant.CacheConstant;
import com.kandinfo.base.admin.constant.PermissionConstant;
import com.kandinfo.base.common.converter.ConverterService;
import com.kandinfo.base.common.dto.widget.DataTablesRequestDto;
import com.kandinfo.base.common.dto.widget.DataTablesResponseDto;
import com.kandinfo.base.security.domain.Permission;
import com.kandinfo.base.security.domain.Role;
import com.kandinfo.base.security.dto.MenuDto;
import com.kandinfo.base.security.dto.RoleDto;
import com.kandinfo.base.security.dto.RoleSearchDto;
import com.kandinfo.base.security.repository.PermissionRepository;
import com.kandinfo.base.security.repository.RoleRepository;
import com.kandinfo.base.security.service.RoleService;

/**
 * 
 * Class Name: RoleServiceImpl Description: RoleServiceImpl
 * 
 * @author qianqiao
 *
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private PermissionRepository permissionRepository;

    @Override
    public Role findById(Long id) {
        return roleRepository.findOne(id);
    }

    @Override
    public Role save(Role role) {
        return roleRepository.save(role);
    }

    @Override
    public DataTablesResponseDto<RoleDto> searchByCon(final RoleSearchDto searchDto) {
        Pageable pageRequest = buildPageRequest(searchDto);
        Specification<Role> specification = new Specification<Role>() {
            @Override
            public Predicate toPredicate(Root<Role> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.conjunction();
                if (searchDto != null) {
                    if (StringUtils.isNotBlank(searchDto.getName())) {
                        predicate = cb.or(cb.like(root.<String>get("roleName"), "%" + searchDto.getName() + "%"), cb.like(root.<String>get("roleDesc"), "%" + searchDto.getName() + "%")

                        );
                    }
                }
                return predicate;
            }

        };
        Page<Role> roles = roleRepository.findAll(specification, pageRequest);
        RoleDto dto = null;
        DataTablesResponseDto<RoleDto> responseDtoList = new DataTablesResponseDto<RoleDto>();
        List<RoleDto> itemDtoList = new ArrayList<RoleDto>();
        for (Role role : roles) {
            dto = new RoleDto();
            dto.setId(role.getId());
            dto.setRoleName(role.getRoleName());
            dto.setRoleDesc(role.getRoleDesc());
            dto.setCreatedTs(role.getCreateTs());
            dto.setType(role.getType());
            itemDtoList.add(dto);
        }

        responseDtoList.setEcho(searchDto.getEcho());
        responseDtoList.setData(itemDtoList);
        responseDtoList.setTotalDisplayRecords(roles.getTotalElements());
        responseDtoList.setTotalRecords(roles.getTotalElements());
        return responseDtoList;
    }

    private Pageable buildPageRequest(DataTablesRequestDto requestDto) {
        Sort sort = null;
        List<Integer> sortedColumns = requestDto.getSortedColumns();
        List<String> sortDirections = requestDto.getSortDirections();
        List<String> dataProps = requestDto.getDataProps();
        if (sortedColumns != null) {
            for (Integer item : sortedColumns) {
                String sortColumn = dataProps.get(item);
                int indexOf = 0;
                if (StringUtils.isNotBlank(sortColumn) && sortColumn.endsWith(".text")) {
                    indexOf = sortColumn.lastIndexOf(".text");
                } else if (StringUtils.isNotBlank(sortColumn) && sortColumn.endsWith(".fullText")) {
                    indexOf = sortColumn.lastIndexOf(".fullText");
                }
                if (indexOf > 0) {
                    sortColumn = sortColumn.substring(0, indexOf);
                }
                String sortDir = sortDirections.get(0);
                sort = new Sort(Direction.fromString(sortDir), sortColumn);
                sort = sort.and(new Sort(Direction.fromString(sortDir), "id"));
            }
        }
        PageRequest page = new PageRequest(requestDto.getDisplayStart() / requestDto.getDisplayLength(),
                requestDto.getDisplayLength(), sort);
        return page;
    }

    @Override
    public List<Role> findAll() {
        return roleRepository.findAll();
    }

    @Override
    public void delete(Long id) {
        roleRepository.delete(id);
    }

    @Override
    @Cacheable(value = CacheConstant.MENU_CACHE, key = "'AllMenu'")
    public List<MenuDto> findAllMenu() {
       /* List<Permission> prems = permissionRepository.findAll(new Sort(Direction.ASC, "parentId").and(new Sort(
                Direction.ASC, "index")));*/
        Specification<Permission> spec = new Specification<Permission>() {
            @Override
            public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.conjunction();
                predicate = cb.or(cb.equal(root.<Integer>get("type"),PermissionConstant.PERM_TYPE_MENU));
                return predicate;
            }

        };
        List<Permission> prems = permissionRepository.findAll(spec, new Sort(Direction.ASC, "parentId").and(new Sort(Direction.ASC, "index")));
        List<MenuDto> root = new ArrayList<MenuDto>();

        Map<Long, Integer> map = new HashMap<Long, Integer>();
        int index = 0;
        for (Permission prem : prems) {
            if (prem.getParentId() == null) {
                MenuDto dto = ConverterService.convert(prem, MenuDto.class);
                dto.setChilds(new ArrayList<MenuDto>());
                dto.setName(prem.getPermDesc());
                map.put(prem.getId(), index);
                root.add(dto);
                index++;
            } else {
                MenuDto dto = ConverterService.convert(prem, MenuDto.class);
                dto.setName(prem.getPermDesc());
                root.get(map.get(prem.getParentId())).getChilds().add(dto);
            }

        }

        return root;
    }

    /**
     * check name
     */
    @Override
    public List<Role> checkName(Long id, String roleName) {
        return roleRepository.checkName(id, roleName);
    }

    @Override
    public List<Role> findRoleNotAdmin() {
        return roleRepository.findRoleNotAdmin();
    }
}
